'/
' GUI Library
' Written by Anton Berlin, 2010.
' 
' =========================================================================
' 
' This program is free software; you can redistribute it and/or modify
' it under the terms of the GNU Lesser General Public License as published
' by the Free Software Foundation; either version 3 of the License.
' 
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' GNU General Public License for more details.
' 
' You should have received a copy of the GNU Lesser General Public License
' along with this program; if not, write to the Free Software
' Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
'/

superstrict

import "GUI_Gadget.bmx"
import "GUI_Def.bmx"

import "../strutil/strutil.bmx"
import "../ArrayList/ArrayList.bmx"

type GUI_List extends GUI_Gadget

	'// -------------------------------------------------------------------------------------------------------------
	'// Update this gadget.
	'// -------------------------------------------------------------------------------------------------------------
	method update()
	
		if (not m_list or not m_list.count()) ..
			return;
		
		if (not mouseHovering()) ..
			return;
		
		if (mouseDown(1)) then
		
			local mx:int = mouseX();
			local my:int = mouseY();
			
			if (mx <= m_posX + m_width and mx >= m_posX + m_width - m_scrollbarSize) then
			
				if (not scroll(my)) ..
					if (my > m_posY + 1) ..
						selectItem(my);
			
			else
			
				if (my > m_posY + 1) ..
					selectItem(my);
			
			end if
		
		end if
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Scroll using the scrollbar.
	'// -------------------------------------------------------------------------------------------------------------
	method scroll:byte(my:int)
	
		setImageFont(m_font);
		
		local totalSize:double = m_height - 2;
		local height:double = textHeight("|");
		
		if (totalSize / height < m_list.count()) then
		
			local posY:int = my - m_scrollbarSize / 2 - m_posY;
			m_markerPosition = posY;
			
			if (m_markerPosition < 0) ..
				m_markerPosition = 0;
			if (m_markerPosition > totalSize - m_scrollbarSize) ..
				m_markerPosition = totalSize - m_scrollbarSize;
			
			m_firstVisibleElement = int( ..
				(m_list.count() - totalSize / height) * ..
				(m_markerPosition / (totalSize - m_scrollbarSize)));
			
			return true;
		
		end if
		
		return false;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Select the item that is below the mx and my coordinate.
	'// -------------------------------------------------------------------------------------------------------------
	method selectItem(my:int)
	
		if (not m_list) ..
			return;
		
		setImageFont(m_font);
		
		local y:int = m_posY + m_resY / 200;
		local text:string;
		local height:int;
		local selected:byte = false;
		
		for local index:int = m_firstVisibleElement until m_list.count()
		
			text = m_list.getElement(index).toString();
			height = textHeight(text);
			
			if (my <= y + height and my >= y) then
			
				m_selected = m_list.getElement(index);
				m_selectedIndex = index;
				selected = true;
				exit;
			
			end if
			
			y :+ height;
		
		next
		
		if (not selected) ..
			m_selected = null;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Draw this gadget.
	'// -------------------------------------------------------------------------------------------------------------
	method draw()
	
		if (not m_visible) ..
			return;
		
		'// Setup the default drawing settings.
		drawutil.setColorInit(m_primitiveR, m_primitiveG, m_primitiveB);
		drawutil.setAlphaInit(m_transparency);
		
		'// Draw the primitive of the gadget.
		drawRect(m_posX, m_posY, m_width, m_height);
		
		'// Draw the design of the gadget.
		design();
		
		'// Reset drawing settings.
		drawutil.resetColor();
		drawutil.resetAlpha();
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Draw the design of this gadget.
	'// -------------------------------------------------------------------------------------------------------------
	method design()
	
		setImageFont(m_font);
		
		local x:int = m_posX + m_resX / 200;
		local y:int = m_posY + m_resY / 200;
		local height:int = textHeight("|");
		
		if (m_list) then
		
			drawSelection(height, x, y);
			drawItems(height, x, y);
			drawBorder();
			drawScrollbar(height);
		
		else
		
			drawBorder();
		
		end if
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Draw the item selection.
	'// -------------------------------------------------------------------------------------------------------------
	method drawSelection(height:int, x:int, y:int)
	
		local text:string;
		local tempIndex:int = -1;
		local scrollbarOffset:int = m_scrollbarSize;
		
		local totalSize:double = m_height - 2;
		
		if (totalSize / height > m_list.count()) ..
			scrollbarOffset = 0;
		
		for local index:int = m_firstVisibleElement until m_list.count()
		
			tempIndex :+ 1;
			
			if (m_selected = m_list.getElement(index)) then
			
				text = m_list.getElement(index).toString();
				height = textHeight(text);
				
				if (m_posY + height * (tempIndex + 1) > m_posY + m_height) ..
					exit;
				
				setColor(m_selectionR, m_selectionG, m_selectionB);
				drawRect(m_posX + 2, y + height * tempIndex, m_width - 3 - scrollbarOffset, height + 1);
				
				exit;
			
			end if
		
		next
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Draw the list items.
	'// -------------------------------------------------------------------------------------------------------------
	method drawItems(height:int, x:int, y:int)
	
		local text:string;
		local newY:int;
		local tempIndex:int = -1;
		
		for local index:int = m_firstVisibleElement until m_list.count()
		
			tempIndex :+ 1;
			newY = y - 2 + height * tempIndex;
			
			if (newY + height <= m_posY + m_height) then
			
				text = m_list.getElement(index).toString();
				height = textHeight(text);
				
				'// Shadow.
				if (m_useShadows) then
				
					setAlpha(m_transparency * 0.5);
					setColor(0, 0, 0);
					drawText(text, x + 3, newY + 3);
				
				end if
				
				'// Upper border.
				if (m_useBorders) then
				
					setAlpha(m_transparency * 1.0);
					setColor(m_textColorR * 0.1, m_textColorG * 0.1, m_textColorB * 0.1)
					drawText(text, x, newY);
					setAlpha(m_transparency * 1.0);
					setColor(m_textColorR * 0.1, m_textColorG * 0.1, m_textColorB * 0.1)
					drawText(text, x, newY + 1);
					setColor(m_textColorR * 0.1, m_textColorG * 0.1, m_textColorB * 0.1)
					drawText(text, x + 1, newY);
					
					'// Lower border.
					setColor(m_textColorR * 0.1, m_textColorG * 0.1, m_textColorB * 0.1)
					drawText(text, x + 2, newY + 2);
				
				end if
				
				'// Main text.
				if (m_list.getElement(index) = m_selected) then
				
					setColor(255 - m_textColorR, 255 - m_textColorG, 255 - m_textColorB);
					drawText(text, x + 1, newY + 1);
				
				else
				
					setColor(m_textColorR, m_textColorG, m_textColorB);
					drawText(text, x + 1, newY + 1);
				
				end if
			
			else
			
				exit;
			
			end if
		
		next
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Draw the borders of the list.
	'// -------------------------------------------------------------------------------------------------------------
	method drawBorder()
	
		setColor(m_primitiveR * 0.5, m_primitiveG * 0.5, m_primitiveB * 0.5);
		drawLine(m_posX, m_posY, m_posX + m_width, m_posY, false);
		drawLine(m_posX, m_posY, m_posX, m_posY + m_height, false);
		setColor(m_primitiveR * 1.5, m_primitiveG * 1.5, m_primitiveB * 1.5);
		drawLine(m_posX, m_posY + m_height, m_posX + m_width, m_posY + m_height, false);
		drawLine(m_posX + m_width, m_posY, m_posX + m_width, m_posY + m_height, false);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Draw the scrollbar.
	'// -------------------------------------------------------------------------------------------------------------
	method drawScrollbar(height:int)
	
		if ((m_height - 2) / height < m_list.count()) then
		
			'// ------------ Scroll Bar -----------
			
			local scrollX:int = m_posX + m_width - m_scrollbarSize;
			local scrollY:int = m_posY + 1;
			
			setColor(m_scrollBarR, m_scrollBarG, m_scrollBarB);
			drawRect(scrollX, scrollY, m_scrollbarSize, m_height - 1);
			
			'// ------------ Scroll Marker -----------
			
			local steps:int = m_list.count() / height;
			local markerY:int = scrollY + m_markerPosition;
			
			setColor(m_scrollbarR * 0.92, m_scrollbarG * 0.92, m_scrollbarB * 0.92);
			drawRect(scrollX, markerY, m_scrollbarSize - 1, m_scrollbarSize);
			setColor(m_primitiveR * 1.5, m_primitiveR * 1.5, m_primitiveR * 1.5);
			drawLine(scrollX, markerY, scrollX + m_scrollbarSize - 1, markerY, false);
			drawLine(scrollX, markerY, scrollX, markerY + m_scrollbarSize, false);
			setColor(m_primitiveR * 0.5, m_primitiveR * 0.5, m_primitiveR * 0.5);
			drawLine(scrollX, markerY + m_scrollbarSize, scrollX + m_scrollbarSize, markerY + m_scrollbarSize, false);
			drawLine(scrollX + m_scrollbarSize - 1, markerY, scrollX + m_scrollbarSize - 1, markerY + m_scrollbarSize, false);
		
		end if
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the color of the form input text.
	'// -------------------------------------------------------------------------------------------------------------
	method setTextColor(r:byte, g:byte, b:byte)
	
		m_textColorR = r;
		m_textColorG = g;
		m_textColorB = b;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the color of the item selection.
	'// -------------------------------------------------------------------------------------------------------------
	method setSelectionColor(r:byte, g:byte, b:byte)
	
		m_selectionR = r;
		m_selectionG = g;
		m_selectionB = b;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the color of the scrollbar.
	'// -------------------------------------------------------------------------------------------------------------
	method setScrollbarColor(r:byte, g:byte, b:byte)
	
		m_scrollbarR = r;
		m_scrollbarG = g;
		m_scrollbarB = b;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the font of the form input text.
	'// -------------------------------------------------------------------------------------------------------------
	method setFont(font:TImageFont)
	
		m_font = font;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set which array list this gadget should represent.
	'// -------------------------------------------------------------------------------------------------------------
	method setList(list:ArrayList)
	
		m_list = list;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set whether or not to use shadows on the item text.
	'// -------------------------------------------------------------------------------------------------------------
	method setTextShadowUsage(value:byte)
	
		m_useShadows = value;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set whether or not to use borders on the item text.
	'// -------------------------------------------------------------------------------------------------------------
	method setTextBorderUsage(value:byte)
	
		m_useBorders = value;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the first visible element in the list.
	'// -------------------------------------------------------------------------------------------------------------
	method setFirstVisibleElement(value:int)
	
		m_firstVisibleElement = value;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the scrollbar size, in pixels.
	'// -------------------------------------------------------------------------------------------------------------
	method setScrollbarSize(value:short)
	
		m_scrollbarSize = value;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Return the selected item as a string.
	'// -------------------------------------------------------------------------------------------------------------
	method selectedItemAsString:string()
	
		return string(m_selected);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// The position of the marker. Min: 0. Max: "height of the gadget" - 2.
	'// -------------------------------------------------------------------------------------------------------------
	field m_markerPosition:int = 0;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// The font to use on the form input text.
	'// -------------------------------------------------------------------------------------------------------------
	field m_font:TImageFont;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Form input text color.
	'// -------------------------------------------------------------------------------------------------------------
	field m_textColorR:byte;
	field m_textColorG:byte;
	field m_textColorB:byte;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Selection color.
	'// -------------------------------------------------------------------------------------------------------------
	field m_selectionR:byte = 0;
	field m_selectionG:byte = 0;
	field m_selectionB:byte = 128;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Scrollbar base color.
	'// -------------------------------------------------------------------------------------------------------------
	field m_scrollbarR:byte = 232;
	field m_scrollbarG:byte = 228;
	field m_scrollbarB:byte = 220;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Size of the scrollbar, in pixels.
	'// -------------------------------------------------------------------------------------------------------------
	field m_scrollbarSize:short = 12;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// A pointer to the array list that this object is going to represent.
	'// -------------------------------------------------------------------------------------------------------------
	field m_list:ArrayList;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Which element in the array list that is visible at the top of the list.
	'// -------------------------------------------------------------------------------------------------------------
	field m_firstVisibleElement:int = 0;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Flag that determines whether or not to use shadows on the item text.
	'// -------------------------------------------------------------------------------------------------------------
	field m_useShadows:byte = false;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Flag that determines whether or not to use borders on the item text.
	'// -------------------------------------------------------------------------------------------------------------
	field m_useBorders:byte = false;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// True if this form is currently selected.
	'// -------------------------------------------------------------------------------------------------------------
	field m_selected:object;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Returns the index of the selected item in the array list.
	'// -------------------------------------------------------------------------------------------------------------
	field m_selectedIndex:int;

end type

